#include "ProtocoloTracker.h"
#include "ElementoBencode.h"
#include "IntegerBencode.h"
#include "CadenaBencode.h"
#include "ListaBencode.h"
#include "DiccionarioBencode.h"
#include "BencodeParser.h"
#include "RespuestaTracker.h"


ProtocoloTracker::ProtocoloTracker() {
}

ProtocoloTracker::~ProtocoloTracker() {
}

string ProtocoloTracker::announceTracker(const string &announce, const string &infoHash, const string &peerId,
		const unsigned long int puerto, const string &subido,
		const string &bajado, const string &falta,
		const bool &compact, const string &trackerid, const string &event, const unsigned int cantidadPeers){

	string aux;

	stringstream ss;

	aux.append("GET /");
	aux.append(announce);
	aux.append("?info_hash=");
	aux.append(infoHash);
	aux.append("&peer_id=");
	aux.append(peerId);
	aux.append("&port=");

	ss.str(""); //TODO usar funciones
	ss << puerto;
	aux.append(ss.str());

	aux.append("&uploaded=");
	aux.append(subido);
	aux.append("&downloaded=");
	aux.append(bajado);
	aux.append("&left=");
	aux.append(falta);

	aux.append("compact=");
	ss.str("");
	ss << compact;
	aux.append(ss.str());


	if(event.size() != 0){
		aux.append("&event=");
		aux.append(event);
	}

	if(trackerid.size() != 0){
		aux.append("&trackerid=");
		aux.append(trackerid);
	}

	aux.append("&numwant=");
	ss.str("");
	ss << cantidadPeers;
	aux.append(ss.str());

	aux.append(" HTTP/1.0\r\n\r\n");

	return aux;
}

Respuesta* ProtocoloTracker::procesar(const string &s) const{

	BencodeParser parser;
	int intervalo = -1;
	int cantSeeds = 0;
	int cantLeechs = 0;
	string trackerId;
	vector<Peer> peers;

	stringstream ss(s);

	DiccionarioBencode* dic = (DiccionarioBencode*)parser.getElemento(ss);

	if ( dic->getTipo() != 'd'){
		parser.borrarRecursosInstanciados(dic);
		return NULL;
	}

	ElementoBencode* elementoIntervalo = (*dic->getDiccionario())["interval"];

	if ( elementoIntervalo != NULL ) {
		intervalo = ((IntegerBencode*)elementoIntervalo)->getValor();
	}

	ElementoBencode* elementoSeeds = (*dic->getDiccionario())["complete"];

	if ( elementoSeeds != NULL ) {
		cantSeeds = ((IntegerBencode*)elementoSeeds)->getValor();
	}

	ElementoBencode* elementoLeechs = (*dic->getDiccionario())["incomplete"];

	if ( elementoLeechs != NULL ) {
		cantLeechs = ((IntegerBencode*)elementoLeechs)->getValor();
	}

	ElementoBencode* elementoTrackerId = (*dic->getDiccionario())["tracker id"];

	if ( elementoTrackerId != NULL ) {
		trackerId = ((CadenaBencode*)elementoTrackerId)->getValor();
	}


	ElementoBencode* elementoPeers = (*dic->getDiccionario())["peers"];

	/* peers puede ser de tipo lista o de tipo cadena,
	 * dependiendo del formato en el que respondio el tracker.
	 * Lista : No Compact. Cadena : compact.
	 */
	if ( elementoPeers->getTipo() == 'l' ) { /*No compact*/

		list<ElementoBencode*>* listaPeers = ((ListaBencode*)elementoPeers)->getLista();

		list<ElementoBencode*>::iterator it = listaPeers->begin();

		for ( ; it != listaPeers->end() ; it++) {
			DiccionarioBencode* diccionario = ((DiccionarioBencode*)*it);

			CadenaBencode* peerId = (CadenaBencode*)(*diccionario->getDiccionario())["peer id"];
			CadenaBencode* peerIp = (CadenaBencode*)(*diccionario->getDiccionario())["ip"];
			IntegerBencode* peerPuerto = (IntegerBencode*)(*diccionario->getDiccionario())["port"];
			Peer peer;

			if ( peerId != NULL ) {
				peer.id = peerId->getValor();
				//cout << "Id " << peer.id <<endl;
			}

			if ( peerIp != NULL ) {
				peer.ip = peerIp->getValor();
				//cout << "Ip " << peer.ip <<endl;
			}

			if ( peerPuerto != NULL ) {
				peer.puerto = peerPuerto->getValor();
				//cout << "Puerto " << peer.puerto <<endl;
			}
			//cout << endl;
			peers.push_back(peer);
		}
	} else {
		string stream = ((CadenaBencode*)elementoPeers)->getValor();

		for ( unsigned int i = 0 ; i < stream.size() ; i += 6 ) {
			string aux(stream,i,6);
			string ip(aux,0,4);
			string puertoStr(aux,4,2);
			unsigned char ipC[5];
			ipC[4] = '\0';

			Peer peer;

			memcpy(ipC, ip.c_str(), 4);
			memcpy(&(peer.puerto), puertoStr.c_str(), 2);

			peer.puerto = ntohs(peer.puerto);


			char componenteIp[4];

			peer.id = "";
			peer.ip = "";

			for(int i = 0; i < 3; i++) {

				int cantDigitos = sprintf(componenteIp,"%d", ipC[i]);
				peer.ip.append(componenteIp,cantDigitos);
				peer.ip += ".";
			}

			int cantDigitos = sprintf(componenteIp,"%d", ipC[3]);
			peer.ip.append(componenteIp,cantDigitos);


			//			cout << "puerto " << peer.puerto << endl;
			//			cout << "ip " << peer.ip << endl;
			//			cout << endl;
			peers.push_back(peer);

		}
	}
	cout << " Respuesta del tracker " << endl;
	parser.borrarRecursosInstanciados(dic);
	return new RespuestaTracker(intervalo,cantSeeds,cantLeechs,trackerId,peers);
}
